The C# Station Tutorial
by Joe Mayo
created 07/04/08, updated 1/12/09
Lesson 22: Topics on C# Type
Throughout this tutorial, you've seen many different types, including those that
are part of C# and custom designed types. If you've taken the samples and worked
on them yourself, extending and writing your own programs, you are likely to have
experienced errors associated with type. For example, you can't assign a
double
to an int without using a cast operator to perform the conversion. Another feature
of C# concerns the semantic differences between reference and value types. Such
problems should make you wonder why this is so and that's what this lesson is for.
Here are the objectives for this lesson:
- Understand the need for type safety
- See how to convert one type to another
- Learn about reference types
- Learn about value types
- Comprehend the semantic differences between reference and value types
Why Type Safety?
In untyped languages, such as scripting languages, you can assign one variable to
another and the compiler/interpreter will use an intelligent algorithm to figure
out how the assignment should be done. If the assignment is between two variables
of the same type, all is good. However, if the assignment is between different
types, you could have serious problems.
For example, if you assigned an int value to a float variable it would convert okay
because the fractional part of the new float would just be zero. However, if you
went the other way and assigned a float value to an int variable, that would most
likely be a problem. You would lose all of the precision of the original float
value. Consider the damage that could be caused if the float value represented
a chemical ingredient, an engineering measurement, or a financial value. Finding
such an error would be difficult and particularly expensive, especially if the error
didn't show up until your application was in production (already being used by customers).
Using the Cast Operator for Conversions
In Lesson 02: Operators, Types, and Variables, you learned about C# types and operators.
It explained the size and precision of the various types and there is a list of
available operators. The cast operator, (x), is listed first as a primary operator
in Table 2-4. When you must convert a type that doesn't fit, it must be done
via what is called an explicit conversion, which uses the cast operator. Listing
22-1 has an example of an implicit conversion, which doesn't require the cast
operator, and an explicit conversion.
Listing 22-1. Cast Operators
using System;
class Program
{
static void Main()
{
float lengthFloat = 7.35f;
// lose precision - explicit conversion
int lengthInt = (int)lengthFloat;
// no problem - implicit conversion
double lengthDouble = lengthInt;
Console.WriteLine("lengthInt =
" + lengthInt);
Console.WriteLine("lengthDouble
= " + lengthDouble);
Console.ReadKey();
}
}
Here's the output:
lengthInt = 7
lengthDouble = 7
Since a float, lengthFloat, has a fractional part but an int,
lengthInt, doesn't;
the types aren't compatible. Because of type safety, C# won't allow you
to assign lengthFloat directly to lengthInt, which would be dangerous. For your
protection, you must use a cast operator, (int), to force the explicit conversion
of lengthFloat to lengthInt. In the output, you can see that lengthInt is
7, showing
that it lost the fractional part of the 7.35f value from lengthFloat.
The assignment from lengthInt to lengthDouble is safe because a double is 64-bit
and an int is 32-bit, meaning that you won't lose information. Therefore, the
conversion is implicit, meaning that you can perform the assignment without the
cast operator.
Understanding Reference Types
Reference type variables are named appropriately (reference) because the variable
holds a reference to an object. In C and C++, you have something similar that is
called a pointer, which points to an object. While you can modify a pointer, you
can't modify the value of a reference - it simply points at the object in memory.
An important fact you need to understand is that when you are assigning one reference
type variable to another, only the reference is copied, not the object. The
variable holds the reference and that is what is being copied. Listing 22-2 shows
how this works.
Listing 22-2. Reference Type Assignment
using System;
class Employee
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = value; }
}
}
class Program
{
static void Main()
{
Employee joe = new Employee();
joe.Name = "Joe";
Employee bob = new Employee();
bob.Name = "Bob";
Console.WriteLine("Original Employee Values:");
Console.WriteLine("joe = " + joe.Name);
Console.WriteLine("bob = " + bob.Name);
// assign joe reference to bob variable
bob = joe;
Console.WriteLine();
Console.WriteLine("Values After Reference Assignment:");
Console.WriteLine("joe = " + joe.Name);
Console.WriteLine("bob = " + bob.Name);
joe.Name = "Bobbi Jo";
Console.WriteLine();
Console.WriteLine("Values After Changing One Instance:");
Console.WriteLine("joe = " + joe.Name);
Console.WriteLine("bob = " + bob.Name);
Console.ReadKey();
}
}
Here's the output:
Original Employee Values:
joe = Joe
bob = Bob
Values After Reference Assignment:
joe = Joe
bob = Joe
Values After Changing One Instance:
joe = Bobbi Jo
bob = Bobbi Jo
In Listing 22-2, I created two Employee instances, joe and bob. You can see in the
output that the Name properties of both Employee instances each show their assigned
values from when the objects were first created. After assigning joe to
bob, the
value of the Name properties of both instances are the same. This is what you might
expect to see.
What might surprise you is the values that occur after assigning a value to the
Employee instance variable named joe. If you look at the code closely, you'll
notice that it doesn't change bob - only Joe. However, the results from the
output show that the Name property in bob is the same as the Name property in
joe.
This demonstrates that after assigning joe to bob, both variables held references
to the joe object. Only the reference was copied - not the object. This is why you
see the results of printing Name in both joe and bob are the same because the change
was on the object that they both refer to.
The following types are reference types:
- arrays
- class'
- delegates
- interfaces
Understanding Value Types
Value type variables, as their name (value) suggests, hold the object value. A value
type variable holds its own copy of an object and when you perform assignment from
one value type variable to another, both the left-hand-side and right-hand-side
of the assignment hold two separate copies of that value. Listing 22-3 shows how
value type assignment works.
Listing 22-3. Value Type Assignment
using System;
struct Height
{
private int m_inches;
public int Inches
{
get { return m_inches; }
set { m_inches = value; }
}
}
class Program
{
static void Main()
{
Height joe = new Height();
joe.Inches = 71;
Height bob = new Height();
bob.Inches = 59;
Console.WriteLine("Original Height
Values:");
Console.WriteLine("joe = " + joe.Inches);
Console.WriteLine("bob = " + bob.Inches);
// assign joe reference to bob variable
bob = joe;
Console.WriteLine();
Console.WriteLine("Values After
Value Assignment:");
Console.WriteLine("joe = " + joe.Inches);
Console.WriteLine("bob = " + bob.Inches);
joe.Inches = 65;
Console.WriteLine();
Console.WriteLine("Values After
Changing One Instance:");
Console.WriteLine("joe = " + joe.Inches);
Console.WriteLine("bob = " + bob.Inches);
Console.ReadKey();
}
}
Here's the output:
Original Height Values:
joe = 71
bob = 59
Values After Value Assignment:
joe = 71
bob = 71
Values After Changing One Instance:
joe = 65
bob = 71
In Listing 22-3, you can see that the Inches property of bob and
joe are initially
set to different values. After assigning joe to bob, a value copy occurs, where
both of the variables have the same value, but are two separate copies. To demonstrate
value assignment results, notice what happens after setting joe to 65; The output
shows that bob did not change, which demonstrates that value types hold distinct
copies of their objects.
The following types are value types:
Reference Type and Value Type Differences
From the previous paragraphs, you might already see that there is a difference reference
type and value type assignment. Reference types copy a reference to an object and
value types copy the object. If you don't know this, then the effects can be
surprising in your code when performing tasks such as making assignments and passing
arguments to methods.
Summary
This lesson provided a few tips on working with types in C#. You should now have
a better understanding of type safety and how it can help you avoid problems. This
lesson showed you how to use a cast operator to perform conversions and explained
the difference between explicit and implicit conversions. You also know that the
type system is divided between reference types and value types. To demonstrate the
differences between reference types and value types, this lesson provided examples
that showed how both reference types and value types behave during assignment.
I invite you to return for Lesson 23: Working with
Nullable Types.
Your feedback and constructive contributions are welcome. Please feel free
to contact me for feedback or comments you may have about this lesson.
Copyright © 2000-2010 C# Station, All Rights Reserved